package com.william.jdbcplus.core.meta;

import com.william.jdbcplus.common.annotation.*;
import com.william.jdbcplus.common.entity.Entity;
import com.william.jdbcplus.common.enums.FieldEnum;
import com.william.jdbcplus.common.enums.IdType;
import com.william.jdbcplus.core.property.JdbcPlusProperties;
import com.william.jdbcplus.core.toolkit.*;
import lombok.extern.slf4j.Slf4j;

import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.sql.Types;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;

import static java.util.stream.Collectors.joining;
import static java.util.stream.Collectors.toList;

/**
 * <p>
 * 实体类反射表辅助类
 * </p>
 */
@Slf4j
public class TableHelperUtil {
    /**
     * 储存反射类表信息
     */
    private static final Map<Class<?>, TableInfo> TABLE_INFO_CACHE = new ConcurrentHashMap<>();

    public TableHelperUtil(String entityPackage) {
        initCache(entityPackage);
    }

    /**
     * 静态初始化
     */
    static {
        // initCache(JdbcPlusProperties.getEntityPackage());
    }

    /**
     * 初始化表缓存信息
     */
    private static void initCache(String entityPackage) {
        @SuppressWarnings("rawtypes")
        Set<Class<? extends Entity>> entityClassSet = ReflectionsUtil.getSubClassSet(Entity.class, entityPackage);
        for (Class<?> entityClass : entityClassSet) {
            initTableInfo(entityClass);
        }
    }

    /**
     * <p>
     * 获取实体映射表信息
     * </p>
     *
     * @param clazz 反射实体类
     * @return 数据库表反射信息
     */
    public static TableInfo getTableInfo(Class<?> clazz) {
        if (clazz == null || ReflectionKit.isPrimitiveOrWrapper(clazz) || clazz == String.class) {
            return null;
        }
        TableInfo tableInfo = TABLE_INFO_CACHE.get(ClassUtils.getUserClass(clazz));
        if (null != tableInfo) {
            return tableInfo;
        }
        //尝试获取父类缓存
        Class<?> currentClass = clazz;
        while (null == tableInfo && Object.class != currentClass) {
            currentClass = currentClass.getSuperclass();
            tableInfo = TABLE_INFO_CACHE.get(ClassUtils.getUserClass(currentClass));
        }
        if (tableInfo != null) {
            TABLE_INFO_CACHE.put(ClassUtils.getUserClass(clazz), tableInfo);
        }

        if (tableInfo == null) {
            tableInfo = initTableInfo(clazz);
        }
        return tableInfo;
    }

    /**
     * <p>
     * 获取所有实体映射表信息
     * </p>
     *
     * @return 数据库表反射信息集合
     */
    public static List<TableInfo> getTableInfos() {
        return new ArrayList<>(TABLE_INFO_CACHE.values());
    }

    /**
     * 获取所有逻辑表名
     *
     * @return
     */
    public static List<String> getTableNames() {
        List<TableInfo> tableInfos = getTableInfos();
        return tableInfos.stream().map(e -> e.getTableName()).collect(Collectors.toList());
    }

    /**
     * <p>
     * 实体类反射获取表信息【初始化】
     * </p>
     *
     * @param clazz 反射实体类
     * @return 数据库表反射信息
     */
    private synchronized static TableInfo initTableInfo(Class<?> clazz) {
        TableInfo tableInfo = TABLE_INFO_CACHE.get(clazz);
        if (tableInfo != null) {
            return tableInfo;
        }

        /* 没有获取到缓存信息,则初始化 */
        tableInfo = new TableInfo(clazz);

        /* 初始化表名相关 */
        initTableName(clazz, tableInfo);

        /* 初始化主键相关 */
        initTablePk(clazz, tableInfo);

        /* 初始化字段相关 */
        initTableFields(clazz, tableInfo);

        /* 初始化唯一键相关 */
        initTableUks(clazz, tableInfo);

        /* 初始化索引相关 */
        initTableIndexs(clazz, tableInfo);

        /* 初始化外键相关 */
        initTableFks(clazz, tableInfo);

        /* 放入缓存 */
        TABLE_INFO_CACHE.put(clazz, tableInfo);

        return tableInfo;
    }

    /**
     * <p>
     * 初始化 表数据库类型,表名,resultMap
     * </p>
     *
     * @param clazz     实体类
     * @param tableInfo 数据库表反射信息
     */
    private static void initTableName(Class<?> clazz, TableInfo tableInfo) {
        /* 数据库全局配置 */
        Table table = clazz.getAnnotation(Table.class);
        //默认值为类简单名转下划线
        String tableName = JdbcPlusProperties.isColumnUnderline() ? StringUtil.humpToUnderline(clazz.getSimpleName()) : clazz.getSimpleName();
        String tableRemarks = clazz.getSimpleName();

        if (table != null) {
            if (StringUtil.isNotBlank(table.value())) {
                tableName = table.value();
                tableRemarks = table.remarks();
                if (StringUtil.isBlank(tableRemarks)) {
                    tableRemarks = tableName;
                }
            }
        }

        tableInfo.setTableName(tableName);
        tableInfo.setTableRemarks(tableRemarks);
    }

    /**
     * 获取对象表名
     *
     * @param clazz
     * @return
     */
    public static String getTableName(Class<?> clazz) {
        String tableName = JdbcPlusProperties.isColumnUnderline() ? StringUtil.humpToUnderline(clazz.getSimpleName()) : clazz.getSimpleName();
        Table table = clazz.getAnnotation(Table.class);
        if (table != null) {
            if (StringUtil.isNotBlank(table.value())) {
                tableName = table.value();
            }
        }

        return tableName;
    }

    /**
     * <p>
     * 初始化索引信息
     * </p>
     *
     * @param clazz     实体类
     * @param tableInfo 数据库表反射信息
     */
    private static void initTableIndexs(Class<?> clazz, TableInfo tableInfo) {
        TableIndexs indexs = clazz.getAnnotation(TableIndexs.class);
        if (indexs != null) {
            if (indexs.value().length > 0) {
                TableIndex[] tableIndices = indexs.value();
                for (TableIndex index : tableIndices) {
                    List<String> columns = new ArrayList<>();
                    String[] fields = index.fields();
                    for (String field : fields) {
                        TableColumnInfo columnInfo = tableInfo.getColumnList().stream().filter(e -> e.getProperty().equals(field)).findFirst().orElse(null);
                        if (columnInfo != null) {
                            columns.add(columnInfo.getColumn());
                        }
                    }
                    if (columns.size() > 0) {
                        columns.sort(String::compareTo);
                        TableIndexInfo indexInfo = new TableIndexInfo();
                        indexInfo.setColumns(columns);
                        indexInfo.setUnique(index.isUnique());
                        indexInfo.setTableName(tableInfo.getTableName());
                        indexInfo.setColumnNames(columns.stream().collect(joining(StringPool.COMMA)));
                        indexInfo.setIndexName("idx_" + tableInfo.getTableName() + StringPool.UNDERSCORE + columns.stream().collect(Collectors.joining(StringPool.UNDERSCORE)));
                        tableInfo.getIndexList().add(indexInfo);
                    }
                }
            }
        }

        int index = 0;
        for (TableIndexInfo indexInfo : tableInfo.getIndexList()) {
            if (indexInfo.getIndexName().length() > 30) {
                index++;
                indexInfo.setShortIndexName(indexInfo.getIndexName().substring(0, 28) + index);
            } else {
                indexInfo.setShortIndexName(indexInfo.getIndexName());
            }
        }
    }

    /**
     * <p>
     * 初始化唯一键信息
     * </p>
     *
     * @param clazz     实体类
     * @param tableInfo 数据库表反射信息
     */
    private static void initTableUks(Class<?> clazz, TableInfo tableInfo) {
        TableUks uks = clazz.getAnnotation(TableUks.class);
        if (uks != null) {
            if (uks.value().length > 0) {
                TableUk[] tableUks = uks.value();
                for (TableUk uk : tableUks) {
                    List<String> columns = new ArrayList<>();
                    String[] fields = uk.fields();
                    for (String field : fields) {
                        TableColumnInfo columnInfo = tableInfo.getColumnList().stream().filter(e -> e.getProperty().equals(field)).findFirst().orElse(null);
                        if (columnInfo != null) {
                            columns.add(columnInfo.getColumn());
                        }
                    }
                    if (columns.size() > 0) {
                        columns.sort(String::compareTo);
                        TableUkInfo ukInfo = new TableUkInfo();
                        ukInfo.setColumns(columns);
                        ukInfo.setTableName(tableInfo.getTableName());
                        ukInfo.setColumnNames(columns.stream().collect(joining(StringPool.COMMA)));
                        ukInfo.setUkName("uk_" + tableInfo.getTableName() + StringPool.UNDERSCORE + columns.stream().collect(Collectors.joining(StringPool.UNDERSCORE)));
                        tableInfo.getUkList().add(ukInfo);
                    }
                }
            }
        }

        int index = 0;
        for (TableUkInfo uniqueInfo : tableInfo.getUkList()) {
            if (uniqueInfo.getUkName().length() > 30) {
                index++;
                uniqueInfo.setShortUkName(uniqueInfo.getUkName().substring(0, 28) + index);
            } else {
                uniqueInfo.setShortUkName(uniqueInfo.getUkName());
            }
        }
    }

    /**
     * <p>
     * 初始化外键信息
     * </p>
     *
     * @param clazz     实体类
     * @param tableInfo 数据库表反射信息
     */
    private static void initTableFks(Class<?> clazz, TableInfo tableInfo) {
        int index = 0;
        for (TableFkInfo fkInfo : tableInfo.getFkList()) {
            if (fkInfo.getFkName().length() > 30) {
                index++;
                fkInfo.setShortFkName(fkInfo.getFkName().substring(0, 28) + index);
            } else {
                fkInfo.setShortFkName(fkInfo.getFkName());
            }
            if (fkInfo.getPkColumnUkName().length() > 30) {
                fkInfo.setPkShortColumnUkName(fkInfo.getPkColumnUkName().substring(0, 30));
            } else {
                fkInfo.setPkShortColumnUkName(fkInfo.getPkColumnUkName());
            }
        }
    }

    /**
     * <p>
     * 初始化 表主键,表字段
     * </p>
     *
     * @param clazz     实体类
     * @param tableInfo 数据库表反射信息
     */
    private static void initTablePk(Class<?> clazz, TableInfo tableInfo) {
        List<Field> list = getAllFields(clazz);
        for (Field field : list) {
            /*
             * 主键ID 初始化
             */
            if (isTableId(field)) {
                initTableId(tableInfo, field);
                break;
            }
        }
    }

    /**
     * <p>
     * 初始化 表主键,表字段
     * </p>
     *
     * @param clazz     实体类
     * @param tableInfo 数据库表反射信息
     */
    private static void initTableFields(Class<?> clazz, TableInfo tableInfo) {
        List<Field> list = getAllFields(clazz);
        for (Field field : list) {
            /*
             * 跳过主键
             */
            if (isTableId(field)) {
                continue;
            }

            /* 字段初始化 */
            initTableField(tableInfo, field);
        }
    }

    /**
     * 是否主键ID
     *
     * @param field
     * @return
     */
    private static boolean isTableId(Field field) {
        TableId tableId = field.getAnnotation(TableId.class);
        if (tableId != null) {
            return true;
        }
        return false;
    }

    /**
     * <p>
     * 主键属性初始化
     * </p>
     *
     * @param tableInfo 表信息
     * @param field     字段
     * @return true 继续下一个属性判断，返回 continue;
     */
    private static boolean initTableId(TableInfo tableInfo, Field field) {
        TableId tableId = field.getAnnotation(TableId.class);
        if (tableId != null) {
            if (tableId.type() == null) {
                tableInfo.setIdType(IdType.INPUT);
            } else {
                tableInfo.setIdType(tableId.type());
            }

            /* 字段 */
            String column = field.getName();
            if (StringUtil.isNotBlank(tableId.value())) {
                column = tableId.value();
            } else {
                if (JdbcPlusProperties.isColumnUnderline()) {
                    column = StringUtil.humpToUnderline(column);
                }
            }

            TablePkInfo pkInfo = new TablePkInfo();
            pkInfo.setTableName(tableInfo.getTableName());
            pkInfo.setPkColumn(column);
            pkInfo.setSize(tableId.size());
            pkInfo.setPkField(field.getName());
            pkInfo.setPkName("pk_" + tableInfo.getTableName() + "_" + column);
            if (pkInfo.getPkName().length() > 30) {
                pkInfo.setShortPkName(pkInfo.getPkName().substring(0, 29) + "1");
            } else {
                pkInfo.setShortPkName(pkInfo.getPkName());
            }

            tableInfo.getPkList().add(pkInfo);
            tableInfo.setKeySize(tableId.size());
            tableInfo.setKeyRemarks(StringUtil.isBlank(tableId.remarks()) ? column : tableId.remarks());
            tableInfo.setKeyColumn(column).setKeyProperty(field.getName()).setKeyType(field.getType());

            // 初始化不可改变字段列表
            initTableFieldFinal(tableInfo, field);
            return true;
        }
        return false;
    }

    /**
     * <p>
     * 字段属性初始化
     * </p>
     *
     * @param tableInfo 表信息
     * @return field 字段
     */
    private static void initTableField(TableInfo tableInfo, Field field) {
        /* 获取注解属性，自定义字段 */
        TableColumn tableField = field.getAnnotation(TableColumn.class);
        TableColumnInfo columnInfo = null;
        if (null == tableField) {
            columnInfo = new TableColumnInfo(tableInfo, field);
        } else {
            columnInfo = new TableColumnInfo(tableInfo, field, tableField);
        }

        tableInfo.getColumnList().add(columnInfo);

        // 初始化不可改变字段列表
        initTableFieldFinal(tableInfo, field);

        // 初始化字段唯一键
        initTableColumnUk(tableInfo, columnInfo, field);

        // 初始化字段索引
        initTableColumnIndex(tableInfo, columnInfo, field);

        // 初始化字段外键
        initTableColumnFk(tableInfo, columnInfo, field);
    }

    private static void initTableFieldFinal(TableInfo tableInfo, Field field) {
        TableFinal tableFinal = field.getAnnotation(TableFinal.class);
        if (tableFinal != null) {
            String fieldName = field.getName();
            tableInfo.getFinalFieldList().add(fieldName);
        }
    }

    private static void initTableColumnUk(TableInfo tableInfo, TableColumnInfo columnInfo, Field field) {
        TableUk tableUk = field.getAnnotation(TableUk.class);
        if (tableUk != null) {
            TableUkInfo tableUkInfo = new TableUkInfo();
            tableUkInfo.setTableName(tableInfo.getTableName());
            tableUkInfo.setColumnNames(columnInfo.getColumn());
            tableUkInfo.setUkName("uk_" + tableInfo.getTableName() + "_" + columnInfo.getColumn());
            tableUkInfo.setColumns(Arrays.asList(columnInfo.getColumn()));
            tableInfo.getUkList().add(tableUkInfo);
        }
    }

    private static void initTableColumnIndex(TableInfo tableInfo, TableColumnInfo columnInfo, Field field) {
        TableIndex tableIndex = field.getAnnotation(TableIndex.class);
        if (tableIndex != null) {
            TableIndexInfo indexInfo = new TableIndexInfo();
            indexInfo.setTableName(tableInfo.getTableName());
            indexInfo.setUnique(tableIndex.isUnique());
            indexInfo.setColumnNames(columnInfo.getColumn());
            indexInfo.setIndexName("idx_" + tableInfo.getTableName() + "_" + columnInfo.getColumn());
            indexInfo.setColumns(Arrays.asList(columnInfo.getColumn()));
            tableInfo.getIndexList().add(indexInfo);
        }
    }

    private static void initTableColumnFk(TableInfo tableInfo, TableColumnInfo columnInfo, Field field) {
        TableFk fk = field.getAnnotation(TableFk.class);
        if (fk != null) {
            Class<? extends Entity> pkEntity = fk.pkEntity();
            TableFkInfo tableFkInfo = TableFkInfo.builder()
                    .fkName("fk_" + tableInfo.getTableName() + StringPool.UNDERSCORE + columnInfo.getColumn())
                    .tableName(tableInfo.getTableName())
                    .fkColumnName(columnInfo.getColumn())
                    .pkEntity(pkEntity)
                    .pkColumnName(getEntityFieldColumn(pkEntity, fk.pkField()))
                    .pkColumnUkName("uk_" + getTableName(pkEntity) + "_" + getEntityFieldColumn(pkEntity, fk.pkField()))
                    .pkFieldName(fk.pkField())
                    .pkTableName(getTableName(pkEntity))
                    .build();
            tableInfo.getFkList().add(tableFkInfo);
        }
    }

    /**
     * <p>
     * 获取该类的所有属性列表
     * </p>
     *
     * @param clazz 反射类
     * @return 属性集合
     */
    public static List<Field> getAllFields(Class<?> clazz) {
        List<Field> fieldList = ReflectionKit.getFieldList(ClassUtils.getUserClass(clazz));
        if (CollectionUtils.isNotEmpty(fieldList)) {
            return fieldList.stream().filter(i -> {
                /* 过滤注解非表字段属性 */
                TableColumn tableField = i.getAnnotation(TableColumn.class);
                return (tableField == null || tableField.exist());
            }).collect(toList());
        }
        return fieldList;
    }

    /**
     * 根据类获取字段
     *
     * @param cls       类
     * @param fieldName 字段域名
     * @return
     */
    private static Field getFieldByClass(Class<?> cls, String fieldName) {
        try {
            return cls.getDeclaredField(fieldName);
        } catch (NoSuchFieldException e) {
        }
        return null;
    }

    /**
     * 获取TableField注解值
     *
     * @param entityClass 类名
     * @param filedName   字段名
     * @return
     */
    public static String getEntityFieldColumn(Class<?> entityClass, String filedName) {
        Field field = getFieldByClass(entityClass, filedName);
        String result = JdbcPlusProperties.isColumnUnderline() ? StringUtil.humpToUnderline(filedName) : filedName;
        if (field == null) {
            return result;
        }
        if (field.isAnnotationPresent(TableColumn.class)) {
            TableColumn annotation = field.getAnnotation(TableColumn.class);
            if (StringUtil.isNotBlank(annotation.value())) {
                return annotation.value();
            }
        }
        if (field.isAnnotationPresent(TableId.class)) {
            TableId annotation = field.getAnnotation(TableId.class);
            if (StringUtil.isNotBlank(annotation.value())) {
                return annotation.value();
            }
        }

        return result;
    }


    /**
     * 获取对象主键字段名
     *
     * @param entityClass 类名
     * @return
     */
    public static String getEntityIdFiledName(Class<?> entityClass) {
        List<Field> fields = getAllFields(entityClass);
        String result = "";
        for (Field field : fields) {
            int mod = field.getModifiers();
            if (Modifier.isStatic(mod) || Modifier.isFinal(mod)) {
                continue;
            }
            if (field.isAnnotationPresent(TableId.class)) {
                return field.getName();
            }
        }

        return result;
    }

    /**
     * 获取对象主键字段
     *
     * @param entityClass 类名
     * @return
     */
    public static Field getTableIdFiled(Class<?> entityClass) {
        List<Field> fields = getAllFields(entityClass);
        for (Field field : fields) {
            int mod = field.getModifiers();
            if (Modifier.isStatic(mod) || Modifier.isFinal(mod)) {
                continue;
            }
            if (field.isAnnotationPresent(TableId.class)) {
                return field;
            }
        }

        return null;
    }

    /**
     * 获取对象逻辑删除字段注解值
     *
     * @param entityClass 类名
     * @return
     */
    public static String getTableLogicColumn(Class<?> entityClass) {
        List<Field> fields = getAllFields(entityClass);
        for (Field field : fields) {
            int mod = field.getModifiers();
            if (Modifier.isStatic(mod) || Modifier.isFinal(mod)) {
                continue;
            }

            if (field.isAnnotationPresent(TableLogic.class)) {
                TableLogic annotation = field.getAnnotation(TableLogic.class);
                if (StringUtil.isNotBlank(annotation.value())) {
                    return annotation.value();
                } else {
                    return field.getName();
                }
            }
        }

        return "";
    }

    /**
     * 获取对象逻辑删除字段
     *
     * @param entityClass 类名
     * @return
     */
    public static String getTableLogicFiledName(Class<?> entityClass) {
        List<Field> fields = getAllFields(entityClass);
        for (Field field : fields) {
            int mod = field.getModifiers();
            if (Modifier.isStatic(mod) || Modifier.isFinal(mod)) {
                continue;
            }

            if (field.isAnnotationPresent(TableLogic.class)) {
                return field.getName();
            }
        }

        return "";
    }

    /**
     * 获取对象逻辑删除字段
     *
     * @param entityClass 类名
     * @return
     */
    public static Field getTableLogicFiled(Class<?> entityClass) {
        List<Field> fields = getAllFields(entityClass);
        for (Field field : fields) {
            int mod = field.getModifiers();
            if (Modifier.isStatic(mod) || Modifier.isFinal(mod)) {
                continue;
            }
            if (field.isAnnotationPresent(TableLogic.class)) {
                return field;
            }
        }

        return null;
    }

    /**
     * 获取对象表描述
     *
     * @param entityClass
     * @return
     */
    public static String getEntityRemarks(Class<?> entityClass) {
        if (entityClass.isAnnotationPresent(Table.class)) {
            Table annotation = entityClass.getAnnotation(Table.class);
            if (StringUtil.isNotBlank(annotation.remarks())) {
                return annotation.remarks();
            } else {
                return annotation.value();
            }
        }

        return entityClass.getSimpleName();
    }

    /**
     *  获取对象的全部属性和属性值组成的MAP
     */
    public static Map<String, Object> getEntityAttrMap(Object entity) {
        Map<String, Object> resultMap = new HashMap<String, Object>();
        List<Field> fields = getAllFields(entity.getClass());
        for (Field field : fields) {
            int mod = field.getModifiers();
            if (Modifier.isStatic(mod) || Modifier.isFinal(mod)) {
                continue;
            }

            field.setAccessible(true);
            Object val = null;
            try {
                val = field.get(entity);
                if (val != null) {
                    if (val instanceof Boolean) {
                        Boolean value = (Boolean) val;
                        val = value ? Integer.valueOf(1) : Integer.valueOf(0);
                    } else if (val instanceof BigInteger) {
                        val = ((BigInteger) val).toString();
                    } else if (val instanceof FieldEnum) {
                        val = Integer.valueOf(((FieldEnum) val).getIndex());
                    }
                }
            } catch (Exception e) {
            }
            resultMap.put(field.getName(), val);
        }

        return resultMap;
    }

    /**
     *  获取对象列表的全部属性和属性值组成的 MAP 列表
     */
    public static <M> List<Map<String, Object>> getEntityAttrMapList(List<M> entityList) {
        List<Map<String, Object>> resultMapList = new LinkedList<>();
        if (entityList == null || entityList.size() == 0) {
            return resultMapList;
        }

        Class<?> clazz = entityList.get(0).getClass();
        List<Field> fields = getAllFields(clazz);
        for (M entity : entityList) {
            if (entity == null) {
                continue;
            }
            Map<String, Object> resultMap = new HashMap<String, Object>();
            for (Field field : fields) {
                int mod = field.getModifiers();
                if (Modifier.isStatic(mod) || Modifier.isFinal(mod)) {
                    continue;
                }

                field.setAccessible(true);
                Object val = null;
                try {
                    val = field.get(entity);
                    if (val != null) {
                        if (val instanceof Boolean) {
                            Boolean value = (Boolean) val;
                            val = value ? Integer.valueOf(1) : Integer.valueOf(0);
                        } else if (val instanceof BigInteger) {
                            val = ((BigInteger) val).toString();
                        } else if (val instanceof FieldEnum) {
                            val = Integer.valueOf(((FieldEnum) val).getIndex());
                        }
                    }
                } catch (Exception e) {
                }
                resultMap.put(field.getName(), val);
            }
            resultMapList.add(resultMap);
        }

        return resultMapList;
    }

    /**
     * 根据实体对象获取主键值
     *
     * @param entity 实体对象
     * @return
     */
    public static Object getEntityIdVal(Object entity) {
        if (entity == null) {
            return null;
        }

        Class<?> clazz = entity.getClass();
        return ReflectionKit.getMethodValue(entity, TableHelperUtil.getTableInfo(clazz).getKeyProperty());
    }

    /**
     * 根据对象获取Class
     *
     * @param entity
     * @param <M>
     * @return
     */
    public static <M> Class<M> getEntityClass(M entity) {
        if (entity == null) {
            return null;
        }
        Class<M> clazz = (Class<M>) entity.getClass();
        return clazz;
    }

    public static Object getEntityFieldValue(Object entity, String fieldName) {
        List<Field> fields = getAllFields(entity.getClass());
        for (Field field : fields) {
            int mod = field.getModifiers();
            if (Modifier.isStatic(mod) || Modifier.isFinal(mod)) {
                continue;
            }

            if (field.getName().equals(fieldName)) {
                field.setAccessible(true);
                Object value = null;
                try {
                    value = field.get(entity);
                } catch (Exception e) {
                }
                return value;
            }
        }

        return null;
    }

    /**
     * 获取对象的全部属性和属性值组成的MAP,不包括逻辑删除字段
     */
    public static Map<String, Object> getEntityAttrMapWithoutLogicDelete(Object entity) {
        Map<String, Object> resultMap = new HashMap<>();
        List<Field> fields = getAllFields(entity.getClass());
        for (Field field : fields) {
            int mod = field.getModifiers();
            if (Modifier.isStatic(mod) || Modifier.isFinal(mod)) {
                continue;
            }
            if (field.isAnnotationPresent(TableLogic.class)) {
                continue;
            }
            field.setAccessible(true);
            Object obj = null;
            try {
                obj = field.get(entity);
            } catch (Exception e) {
                e.printStackTrace();
            }
            resultMap.put(field.getName(), obj);
        }

        return resultMap;
    }

    /**
     * 获取全部字段
     * <p>
     * select id, name as name_
     * </p>
     *
     * @param clazz
     * @return
     */
    public static String getSelectAllColumn(Class<?> clazz) {
        TableInfo table = getTableInfo(clazz);
        String tableName = table.getTableName();
        // 用于保存所有字段列
        List<String> columnList = new ArrayList<>(table.getColumnList().size() + 1);
        if (table.getKeyColumn() != null) {
            columnList.add(tableName + StringPool.DOT + table.getKeyColumn() + SQLKeyUtils.asFieldColumn(table.getKeyProperty(), table.getKeyColumn()));
        }
        columnList.addAll(table.getColumnList().stream().map(e -> {
            return tableName + StringPool.DOT + e.getColumn() + SQLKeyUtils.asFieldColumn(e.getProperty(), e.getColumn());
        }).collect(toList()));
        return columnList.stream().collect(joining(StringPool.COMMA));
    }

    /**
     * 获取不带 table. 的表列
     *
     * @param clazz
     * @return
     */
    public static String getSelectAllColumnNoTable(Class<?> clazz) {
        TableInfo table = getTableInfo(clazz);
        // 用于保存所有字段列
        List<String> columnList = new ArrayList<>(table.getColumnList().size() + 1);
        if (table.getKeyColumn() != null) {
            columnList.add(table.getKeyColumn() + SQLKeyUtils.asFieldColumn(table.getKeyProperty(), table.getKeyColumn()));
        }
        columnList.addAll(table.getColumnList().stream().map(e -> {
            return e.getColumn() + SQLKeyUtils.asFieldColumn(e.getProperty(), e.getColumn());
        }).collect(toList()));
        return columnList.stream().collect(joining(StringPool.COMMA));
    }

    /**
     * 获取插入 insert table ( ) 括号之间部分， 带括号
     *
     * @param clazz
     * @return
     */
    public static String getColumnInsert(Class<?> clazz) {
        TableInfo table = getTableInfo(clazz);
        // 用于保存所有字段列
        List<String> columnList = new ArrayList<>(table.getColumnList().size() + 1);
        if (table.getIdType() != IdType.AUTO && table.getKeyColumn() != null) {
            columnList.add(table.getKeyColumn());
        }
        columnList.addAll(table.getColumnList().stream().map(e -> e.getColumn()).collect(toList()));
        return columnList.stream().collect(joining(StringPool.COMMA, StringPool.LEFT_BRACKET, StringPool.RIGHT_BRACKET));
    }

    /**
     * 获取 insert值部分
     *
     * @param clazz
     * @return
     */
    public static String getValuesInsert(Class<?> clazz) {
        TableInfo table = getTableInfo(clazz);
        // 用于保存所有字段列
        List<String> valueList = new ArrayList<>(table.getColumnList().size() + 1);
        if (table.getIdType() != IdType.AUTO && table.getKeyColumn() != null) {
            valueList.add(StringPool.COLON + table.getKeyProperty());
        }
        valueList.addAll(table.getColumnList().stream().map(e -> {
            if (e.isLogicDelete()) {
                if (e.getPropertyType() == String.class) {
                    return StringPool.SINGLE_QUOTE + e.getLogicNotDeleteValue() + StringPool.SINGLE_QUOTE;
                } else {
                    return e.getLogicNotDeleteValue();
                }
            } else {
                return StringPool.COLON + e.getProperty();
            }
        }).collect(toList()));
        return valueList.stream().collect(joining(StringPool.COMMA, StringPool.LEFT_BRACKET, StringPool.RIGHT_BRACKET));
    }

    /**
     * 获取 batchInsert值部分
     *
     * @param clazz
     * @return
     */
    public static String getBatchInsert(Class<?> clazz) {
        TableInfo table = getTableInfo(clazz);
        // 用于保存所有字段列
        List<String> valueList = new ArrayList<>(table.getColumnList().size() + 1);
        if (table.getIdType() != IdType.AUTO && table.getKeyColumn() != null) {
            valueList.add("?");
        }

        for (int i = 0; i < table.getColumnList().size(); i++) {
            valueList.add("?");
        }

        return valueList.stream().collect(joining(StringPool.COMMA, StringPool.LEFT_BRACKET, StringPool.RIGHT_BRACKET));
    }

    public static void setParameterValue(PreparedStatement ps, int paramIndex, Class<?> fieldType, Object inValue) throws SQLException {
        if (FieldEnum.class.isAssignableFrom(fieldType)) {
            if (inValue != null) {
                ps.setInt(paramIndex, (Integer) inValue);
            } else {
                ps.setNull(paramIndex, Types.INTEGER);
            }
        } else if (Short.class.equals(fieldType)) {
            if (inValue != null) {
                ps.setShort(paramIndex, (Short) inValue);
            } else {
                ps.setNull(paramIndex, Types.SMALLINT);
            }
        } else if (Integer.class.equals(fieldType)) {
            if (inValue != null) {
                ps.setInt(paramIndex, (Integer) inValue);
            } else {
                ps.setNull(paramIndex, Types.INTEGER);
            }
        } else if (Long.class.equals(fieldType)) {
            if (inValue != null) {
                ps.setLong(paramIndex, (Long) inValue);
            } else {
                ps.setNull(paramIndex, Types.BIGINT);
            }
        } else if (BigInteger.class.equals(fieldType)) {
            if (inValue != null) {
                ps.setLong(paramIndex, Long.parseLong(inValue.toString()));
            } else {
                ps.setNull(paramIndex, Types.BIGINT);
            }
        } else if (Boolean.class.equals(fieldType)) {
            if (inValue != null) {
                ps.setBoolean(paramIndex, (Boolean) inValue);
            } else {
                ps.setNull(paramIndex, Types.BOOLEAN);
            }
        } else if (Float.class.equals(fieldType)) {
            if (inValue != null) {
                ps.setFloat(paramIndex, (Float) inValue);
            } else {
                ps.setNull(paramIndex, Types.FLOAT);
            }
        } else if (Double.class.equals(fieldType)) {
            if (inValue != null) {
                ps.setDouble(paramIndex, (Double) inValue);
            } else {
                ps.setNull(paramIndex, Types.DOUBLE);
            }
        } else if (BigDecimal.class.equals(fieldType)) {
            if (inValue != null) {
                ps.setBigDecimal(paramIndex, (BigDecimal) inValue);
            } else {
                ps.setNull(paramIndex, Types.DECIMAL);
            }
        } else if (Byte.class.equals(fieldType)) {
            if (inValue != null) {
                ps.setByte(paramIndex, (Byte) inValue);
            } else {
                ps.setNull(paramIndex, Types.BIT);
            }
        } else if (Date.class.equals(fieldType)) {
            if (inValue != null) {
                ps.setDate(paramIndex, new java.sql.Date(((Date) inValue).getTime()));
            } else {
                ps.setNull(paramIndex, Types.DATE);
            }
        } else if (String.class.equals(fieldType)) {
            if (inValue != null) {
                ps.setString(paramIndex, inValue.toString());
            } else {
                ps.setNull(paramIndex, Types.VARCHAR);
            }
        } else {
            if (inValue != null) {
                ps.setString(paramIndex, inValue.toString());
            } else {
                ps.setNull(paramIndex, Types.VARCHAR);
            }
        }
    }

}
